///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file archive.h
///
/// \brief   header file for the binary archiving class
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef PCPS_BINARY_ARCHIVE_HEADER
#define PCPS_BINARY_ARCHIVE_HEADER

#include <fstream>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>

#include <src/exception.h>

namespace pcps {

  class Archive {

    public:

      virtual ~Archive() {} //{ std::cout << "destroyed Archive" << std::endl; }

      virtual bool operator!() const = 0;

      virtual operator void*() const = 0;

      virtual Archive & getline(std::string & str) = 0;
      virtual Archive & getline(std::string & str, char delim) = 0;

      virtual Archive & operator>>(                              bool& val ) = 0;
      virtual Archive & operator>>(                             short& val ) = 0;
      virtual Archive & operator>>(                    unsigned short& val ) = 0;
      virtual Archive & operator>>(                               int& val ) = 0;
      virtual Archive & operator>>(                      unsigned int& val ) = 0;
      virtual Archive & operator>>(                              long& val ) = 0;
      virtual Archive & operator>>(                     unsigned long& val ) = 0;
      virtual Archive & operator>>(                             float& val ) = 0;
      virtual Archive & operator>>(                            double& val ) = 0;
      virtual Archive & operator>>(                       long double& val ) = 0;
      virtual Archive & operator>>(              std::complex<double>& val ) = 0;
      virtual Archive & operator>>(                             void*& val ) = 0;
      virtual Archive & operator>>(                              char& val ) = 0;
      virtual Archive & operator>>(                       signed char& val ) = 0;
      virtual Archive & operator>>(                     unsigned char& val ) = 0;

      //virtual Archive & operator>>(                    std::streambuf*  sb ) = 0;

      //virtual Archive & operator>>(                              char* str ) = 0;
      //virtual Archive & operator>>(                       signed char* str ) = 0;
      //virtual Archive & operator>>(                     unsigned char* str ) = 0;
      virtual Archive & operator>>(                      std::string & str ) = 0;

      virtual Archive & operator>>(   std::istream& ( *pf )(std::istream&) ) = 0;
      virtual Archive & operator>>(           std::ios& ( *pf )(std::ios&) ) = 0;
      virtual Archive & operator>>( std::ios_base& ( *pf )(std::ios_base&) ) = 0;

      virtual Archive & operator>>(                std::vector<short>& val ) = 0;
      virtual Archive & operator>>(       std::vector<unsigned short>& val ) = 0;
      virtual Archive & operator>>(                  std::vector<int>& val ) = 0;
      virtual Archive & operator>>(         std::vector<unsigned int>& val ) = 0;
      virtual Archive & operator>>(                 std::vector<long>& val ) = 0;
      virtual Archive & operator>>(        std::vector<unsigned long>& val ) = 0;
      virtual Archive & operator>>(                std::vector<float>& val ) = 0;
      virtual Archive & operator>>(               std::vector<double>& val ) = 0;
      virtual Archive & operator>>(          std::vector<long double>& val ) = 0;
      virtual Archive & operator>>(                 std::vector<char>& val ) = 0;
      virtual Archive & operator>>(          std::vector<signed char>& val ) = 0;
      virtual Archive & operator>>(        std::vector<unsigned char>& val ) = 0;
      virtual Archive & operator>>(          std::vector<std::string>& val ) = 0;
      virtual Archive & operator>>(std::vector<std::complex<double> >& val ) = 0;

      virtual Archive & operator>>(                   std::set<short>& val ) = 0;
      virtual Archive & operator>>(          std::set<unsigned short>& val ) = 0;
      virtual Archive & operator>>(                     std::set<int>& val ) = 0;
      virtual Archive & operator>>(            std::set<unsigned int>& val ) = 0;
      virtual Archive & operator>>(                    std::set<long>& val ) = 0;
      virtual Archive & operator>>(           std::set<unsigned long>& val ) = 0;
      virtual Archive & operator>>(                    std::set<char>& val ) = 0;
      virtual Archive & operator>>(             std::set<signed char>& val ) = 0;
      virtual Archive & operator>>(           std::set<unsigned char>& val ) = 0;
      virtual Archive & operator>>(             std::set<std::string>& val ) = 0;

      virtual Archive & operator<<(                         const bool val ) = 0;
      virtual Archive & operator<<(                        const short val ) = 0;
      virtual Archive & operator<<(               const unsigned short val ) = 0;
      virtual Archive & operator<<(                          const int val ) = 0;
      virtual Archive & operator<<(                 const unsigned int val ) = 0;
      virtual Archive & operator<<(                         const long val ) = 0;
      virtual Archive & operator<<(                const unsigned long val ) = 0;
      virtual Archive & operator<<(                        const float val ) = 0;
      virtual Archive & operator<<(                       const double val ) = 0;
      virtual Archive & operator<<(                  const long double val ) = 0;
      virtual Archive & operator<<(        const std::complex<double>& val ) = 0;
      virtual Archive & operator<<(                        const void* val ) = 0;
      virtual Archive & operator<<(                         const char val ) = 0;
      virtual Archive & operator<<(                  const signed char val ) = 0;
      virtual Archive & operator<<(                const unsigned char val ) = 0;

      //virtual Archive & operator<<(                    std::streambuf*  sb ) = 0;

      virtual Archive & operator<<(                        const char* str ) = 0;
      //virtual Archive & operator<<(                 const signed char* str ) = 0;
      //virtual Archive & operator<<(               const unsigned char* str ) = 0;
      virtual Archive & operator<<(                const std::string & str ) = 0;

      virtual Archive & operator<<(   std::ostream& ( *pf )(std::ostream&) ) = 0;
      virtual Archive & operator<<(           std::ios& ( *pf )(std::ios&) ) = 0;
      virtual Archive & operator<<( std::ios_base& ( *pf )(std::ios_base&) ) = 0;

      virtual Archive & operator<<(          const std::vector<short>& val ) = 0;
      virtual Archive & operator<<( const std::vector<unsigned short>& val ) = 0;
      virtual Archive & operator<<(            const std::vector<int>& val ) = 0;
      virtual Archive & operator<<(   const std::vector<unsigned int>& val ) = 0;
      virtual Archive & operator<<(           const std::vector<long>& val ) = 0;
      virtual Archive & operator<<(  const std::vector<unsigned long>& val ) = 0;
      virtual Archive & operator<<(          const std::vector<float>& val ) = 0;
      virtual Archive & operator<<(         const std::vector<double>& val ) = 0;
      virtual Archive & operator<<(    const std::vector<long double>& val ) = 0;
      virtual Archive & operator<<(           const std::vector<char>& val ) = 0;
      virtual Archive & operator<<(    const std::vector<signed char>& val ) = 0;
      virtual Archive & operator<<(  const std::vector<unsigned char>& val ) = 0;
      virtual Archive & operator<<(    const std::vector<std::string>& val ) = 0;
      virtual Archive & operator<<( const std::vector<std::complex<double> >& val ) = 0;

      virtual Archive & operator<<(             const std::set<short>& val ) = 0;
      virtual Archive & operator<<(    const std::set<unsigned short>& val ) = 0;
      virtual Archive & operator<<(               const std::set<int>& val ) = 0;
      virtual Archive & operator<<(      const std::set<unsigned int>& val ) = 0;
      virtual Archive & operator<<(              const std::set<long>& val ) = 0;
      virtual Archive & operator<<(     const std::set<unsigned long>& val ) = 0;
      virtual Archive & operator<<(              const std::set<char>& val ) = 0;
      virtual Archive & operator<<(       const std::set<signed char>& val ) = 0;
      virtual Archive & operator<<(     const std::set<unsigned char>& val ) = 0;
      virtual Archive & operator<<(       const std::set<std::string>& val ) = 0;

  };

  template<class T> class TextArchiveTemplate : public pcps::Archive {

    protected:

      boost::shared_ptr<T> _s;

      template<class U> pcps::Archive & write_vector(const std::vector<U> & val) {
        *this << '[' << std::endl;
        for (size_t i = 0; i < val.size(); i++)
          *this << " " << val[i] << std::endl;
        *this << ']' << std::endl;
        return *this;
      }

      template<class U> pcps::Archive & read_vector(std::vector<U> & val) {

        // read in the beginning-of-vector parentheses
        {
          char c;
          *this >> c;
          if (c != '[')
            throw pcps::Exception("expected the \"[\" character at the start of a vector, found \"%s\" instead") % c;
        }

        // read in the body of the vector, which is terminated by a ']' preceeded by whitespace, e.g. " ]"
        std::string vec_text;
        std::getline(*_s, vec_text, ']');
        if ( _s->eof() || _s->fail() )
          throw pcps::Exception("expected a \"]\" character preceeded by whitespace at the end of the vector");

        // count the number of elements and resize the vector
        size_t n = 0;
        {
          std::stringstream vec_stream(vec_text);
          for (U x; vec_stream >> x; n++) {}
        }
        val.resize(n);

        // populate the vector
        {
          std::stringstream vec_stream(vec_text);
          for (size_t i = 0; i < n; i++)
            vec_stream >> val[i];
        }

        // return the archive
        return *this;

      }

      template<class U> pcps::Archive & write_set(const std::set<U> & val) {
        *this << '[' << std::endl;
        for (typename std::set<U>::const_iterator it = val.begin(); it != val.end(); it++)
          *this << " " << *it << std::endl;
        *this << ']' << std::endl;
        return *this;
      }

      template<class U> pcps::Archive & read_set(std::set<U> & val) {
        val.clear();
        std::vector<U> vec;
        *this >> vec;
        val.insert(vec.begin(), vec.end());
        return *this;
      }

    public:

      ~TextArchiveTemplate() {} //{ std::cout << "destroyed TextArchiveTemplate" << std::endl; }

      bool operator!() const { return !(*_s); }

      operator void*() const { return (void *)(*_s); }

      pcps::Archive & getline(std::string & str) { std::getline(*_s, str); }
      pcps::Archive & getline(std::string & str, char delim) { std::getline(*_s, str, delim); }

      pcps::Archive & operator>>(                              bool& val ) { *_s >> std::boolalpha >> val; return *this; }
      pcps::Archive & operator>>(                             short& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                    unsigned short& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                               int& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                      unsigned int& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                              long& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                     unsigned long& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                             float& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                            double& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                       long double& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(             std::complex<double> & val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                             void*& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                              char& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                       signed char& val ) { *_s >> val; return *this; }
      pcps::Archive & operator>>(                     unsigned char& val ) { *_s >> val; return *this; }

      //pcps::Archive & operator>>(                    std::streambuf*  sb ) { *_s >>  sb; return *this; }

      //pcps::Archive & operator>>(                              char* str ) { *_s >> str; return *this; }
      //pcps::Archive & operator>>(                       signed char* str ) { *_s >> str; return *this; }
      //pcps::Archive & operator>>(                     unsigned char* str ) { *_s >> str; return *this; }
      pcps::Archive & operator>>(                      std::string & str ) { *_s >> str; return *this; }

      pcps::Archive & operator>>(   std::istream& ( *pf )(std::istream&) ) { *_s >>  pf; return *this; }
      pcps::Archive & operator>>(           std::ios& ( *pf )(std::ios&) ) { *_s >>  pf; return *this; }
      pcps::Archive & operator>>( std::ios_base& ( *pf )(std::ios_base&) ) { *_s >>  pf; return *this; }

      pcps::Archive & operator>>(                std::vector<short>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(       std::vector<unsigned short>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(                  std::vector<int>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(         std::vector<unsigned int>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(                 std::vector<long>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(        std::vector<unsigned long>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(                std::vector<float>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(               std::vector<double>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(          std::vector<long double>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(                 std::vector<char>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(          std::vector<signed char>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(        std::vector<unsigned char>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(          std::vector<std::string>& val ) { return this->read_vector(val); }
      pcps::Archive & operator>>(std::vector<std::complex<double> >& val ) { return this->read_vector(val); }

      pcps::Archive & operator>>(                   std::set<short>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(          std::set<unsigned short>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(                     std::set<int>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(            std::set<unsigned int>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(                    std::set<long>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(           std::set<unsigned long>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(                    std::set<char>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(             std::set<signed char>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(           std::set<unsigned char>& val ) { return this->read_set(val); }
      pcps::Archive & operator>>(             std::set<std::string>& val ) { return this->read_set(val); }

      pcps::Archive & operator<<(                         const bool val ) { *_s << " " << std::boolalpha << val; return *this; }
      pcps::Archive & operator<<(                        const short val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(               const unsigned short val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                          const int val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                 const unsigned int val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                         const long val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                const unsigned long val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                        const float val ) {
        *_s << " " << std::scientific << std::setprecision(15) << val;
        return *this;
      }
      pcps::Archive & operator<<(                       const double val ) {
        *_s << " " << std::scientific << std::setprecision(15) << val;
        return *this;
      }
      pcps::Archive & operator<<(                  const long double val ) {
        *_s << " " << std::scientific << std::setprecision(15) << val;
        return *this;
      }
      pcps::Archive & operator<<(        const std::complex<double>& val ) {
        *_s << " " << std::scientific << std::setprecision(15) << val;
        return *this;
      }
      pcps::Archive & operator<<(                        const void* val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                         const char val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                  const signed char val ) { *_s << " " << val; return *this; }
      pcps::Archive & operator<<(                const unsigned char val ) { *_s << " " << val; return *this; }

      //pcps::Archive & operator<<(                    std::streambuf*  sb ) { *_s << " " <<  sb; return *this; }

      pcps::Archive & operator<<(                        const char* str ) { *_s << " " << str; return *this; }
      //pcps::Archive & operator<<(                 const signed char* str ) { *_s << " " << str; return *this; }
      //pcps::Archive & operator<<(               const unsigned char* str ) { *_s << " " << str; return *this; }
      pcps::Archive & operator<<(                const std::string & str ) { *_s << " " << str; return *this; }

      pcps::Archive & operator<<(   std::ostream& ( *pf )(std::ostream&) ) { *_s << pf; return *this; }
      pcps::Archive & operator<<(           std::ios& ( *pf )(std::ios&) ) { *_s << pf; return *this; }
      pcps::Archive & operator<<( std::ios_base& ( *pf )(std::ios_base&) ) { *_s << pf; return *this; }

      pcps::Archive & operator<<(          const std::vector<short>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<( const std::vector<unsigned short>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(            const std::vector<int>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(   const std::vector<unsigned int>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(           const std::vector<long>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(  const std::vector<unsigned long>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(          const std::vector<float>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(         const std::vector<double>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(    const std::vector<long double>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(           const std::vector<char>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(    const std::vector<signed char>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(  const std::vector<unsigned char>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<(    const std::vector<std::string>& val ) { return this->write_vector(val); }
      pcps::Archive & operator<<( const std::vector<std::complex<double> >& val ) { return this->write_vector(val); }

      pcps::Archive & operator<<(             const std::set<short>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(    const std::set<unsigned short>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(               const std::set<int>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(      const std::set<unsigned int>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(              const std::set<long>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(     const std::set<unsigned long>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(              const std::set<char>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(       const std::set<signed char>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(     const std::set<unsigned char>& val ) { return this->write_set(val); }
      pcps::Archive & operator<<(       const std::set<std::string>& val ) { return this->write_set(val); }

  };

  class TextArchive : public pcps::TextArchiveTemplate<std::stringstream> {

    private:

      /// \brief  the copy constructor is disabled
      TextArchive(const TextArchive &);

      /// \brief  the assignment operator is disabled
      TextArchive & operator=(const TextArchive &);

    public:

      TextArchive() {
        _s = boost::shared_ptr<std::stringstream>( new std::stringstream() );
      }

      ~TextArchive() {} //{ std::cout << "destroyed TextArchive" << std::endl; }

  };

  class TextFileArchive : public pcps::TextArchiveTemplate<std::fstream> {

    private:

      /// \brief  the copy constructor is disabled
      TextFileArchive(const TextFileArchive &);

      /// \brief  the assignment operator is disabled
      TextFileArchive & operator=(const TextFileArchive &);

    public:

      TextFileArchive(const std::string & filename, const std::string & mode = "rwt") {

        // get the mode in which to open the file
        std::ios_base::openmode which;
        if      (mode == "r")
          which = std::ios_base::in;
        else if (mode == "w")
          which = std::ios_base::out;
        else if (mode == "wt")
          which = std::ios_base::out | std::ios_base::trunc;
        else if (mode == "rw")
          which = std::ios_base::in | std::ios_base::out;
        else if (mode == "rwt")
          which = std::ios_base::in | std::ios_base::out | std::ios_base::trunc;
        else
          throw pcps::Exception("mode for TextFileArchive must be \"r\", \"w\", \"wt\", \"rw\", or \"rwt\"");

        // open the file
        _s = boost::shared_ptr<std::fstream>( new std::fstream(filename.c_str(), which) );

        // verify file is open
        if (!_s->is_open())
          throw pcps::Exception("Failed to open file \"%s\" in TextFileArchive constructor.") % filename;

      }

      ~TextFileArchive() {
        _s->close();
        //std::cout << "destroyed TextFileArchive" << std::endl;
      }

  };

  template<class T> class BinaryArchiveTemplate : public pcps::Archive {

    protected:

      boost::shared_ptr<T> _s;

      template<class U> void write(const U * ptr, const size_t n) {
        _s->write((const char *)ptr, n*sizeof(U));
      }

      template<class U> void read(U * ptr, const size_t n) {
        _s->read((char *)ptr, n*sizeof(U));
      }

      template<class U> pcps::Archive & write(const U & val) {
        this->write(&val, 1);
        return *this;
      }

      template<class U> pcps::Archive & read(U & val) {
        this->read(&val, 1);
        return *this;
      }

      template<class U> pcps::Archive & write(const std::vector<U> & val) {
        const size_t n = val.size();
        this->write(n);
        if (n > 0)
          this->write(&val[0], n);
        return *this;
      }

      template<class U> pcps::Archive & read(std::vector<U> & val) {
        size_t n;
        this->read(n);
        val.resize(n);
        if (n > 0)
          this->read(&val[0], n);
        return *this;
      }

      template<class U> pcps::Archive & write(const std::set<U> & val) {
        const size_t n = val.size();
        this->write(n);
        for (typename std::set<U>::const_iterator it = val.begin(); it != val.end(); it++)
          this->write(U(*it));
        return *this;
      }

      template<class U> pcps::Archive & read(std::set<U> & val) {
        val.clear();
        size_t n;
        this->read(n);
        for (size_t i = 0; i < n; i++) {
          U u;
          this->read(u);
          val.insert(u);
        }
        return *this;
      }

    public:

      ~BinaryArchiveTemplate() {} //{ std::cout << "destroyed BinaryArchiveTemplate" << std::endl; }

      bool operator!() const { return !(*_s); }

      operator void*() const { return (void *)(*_s); }

      pcps::Archive & getline(std::string & str) { std::getline(*_s, str); }
      pcps::Archive & getline(std::string & str, char delim) { std::getline(*_s, str, delim); }

      // define input operators
      pcps::Archive & operator>>(                              bool& val ) { return this->read(val); }
      pcps::Archive & operator>>(                             short& val ) { return this->read(val); }
      pcps::Archive & operator>>(                    unsigned short& val ) { return this->read(val); }
      pcps::Archive & operator>>(                               int& val ) { return this->read(val); }
      pcps::Archive & operator>>(                      unsigned int& val ) { return this->read(val); }
      pcps::Archive & operator>>(                              long& val ) { return this->read(val); }
      pcps::Archive & operator>>(                     unsigned long& val ) { return this->read(val); }
      pcps::Archive & operator>>(                             float& val ) { return this->read(val); }
      pcps::Archive & operator>>(                            double& val ) { return this->read(val); }
      pcps::Archive & operator>>(                       long double& val ) { return this->read(val); }
      pcps::Archive & operator>>(             std::complex<double> & val ) { return this->read(val); }
      pcps::Archive & operator>>(                             void*& val ) { return this->read(val); }
      pcps::Archive & operator>>(                              char& val ) { return this->read(val); }
      pcps::Archive & operator>>(                       signed char& val ) { return this->read(val); }
      pcps::Archive & operator>>(                     unsigned char& val ) { return this->read(val); }

      //pcps::Archive & operator>>(                    std::streambuf*  sb ) { *_s >>  sb; return *this; }

      //pcps::Archive & operator>>(                              char* str ) { return this->rea }
      //pcps::Archive & operator>>(                       signed char* str ) { return this->rea }
      //pcps::Archive & operator>>(                     unsigned char* str ) { return this->rea }
      pcps::Archive & operator>>(                      std::string & val ) {
        std::vector<char> vec;
        *this >> vec;
        val.assign(vec.begin(), vec.end());
        return *this;
      }

      pcps::Archive & operator>>(   std::istream& ( *pf )(std::istream&) ) { return *this; }
      pcps::Archive & operator>>(           std::ios& ( *pf )(std::ios&) ) { return *this; }
      pcps::Archive & operator>>( std::ios_base& ( *pf )(std::ios_base&) ) { return *this; }

      pcps::Archive & operator>>(                std::vector<short>& val ) { return this->read(val); }
      pcps::Archive & operator>>(       std::vector<unsigned short>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                  std::vector<int>& val ) { return this->read(val); }
      pcps::Archive & operator>>(         std::vector<unsigned int>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                 std::vector<long>& val ) { return this->read(val); }
      pcps::Archive & operator>>(        std::vector<unsigned long>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                std::vector<float>& val ) { return this->read(val); }
      pcps::Archive & operator>>(               std::vector<double>& val ) { return this->read(val); }
      pcps::Archive & operator>>(          std::vector<long double>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                 std::vector<char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(          std::vector<signed char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(        std::vector<unsigned char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(          std::vector<std::string>& val ) { return this->read(val); }
      pcps::Archive & operator>>(std::vector<std::complex<double> >& val ) { return this->read(val); }

      pcps::Archive & operator>>(                   std::set<short>& val ) { return this->read(val); }
      pcps::Archive & operator>>(          std::set<unsigned short>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                     std::set<int>& val ) { return this->read(val); }
      pcps::Archive & operator>>(            std::set<unsigned int>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                    std::set<long>& val ) { return this->read(val); }
      pcps::Archive & operator>>(           std::set<unsigned long>& val ) { return this->read(val); }
      pcps::Archive & operator>>(                    std::set<char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(             std::set<signed char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(           std::set<unsigned char>& val ) { return this->read(val); }
      pcps::Archive & operator>>(             std::set<std::string>& val ) { return this->read(val); }

      pcps::Archive & operator<<(                         const bool val ) { return this->write(val); }
      pcps::Archive & operator<<(                        const short val ) { return this->write(val); }
      pcps::Archive & operator<<(               const unsigned short val ) { return this->write(val); }
      pcps::Archive & operator<<(                          const int val ) { return this->write(val); }
      pcps::Archive & operator<<(                 const unsigned int val ) { return this->write(val); }
      pcps::Archive & operator<<(                         const long val ) { return this->write(val); }
      pcps::Archive & operator<<(                const unsigned long val ) { return this->write(val); }
      pcps::Archive & operator<<(                        const float val ) { return this->write(val); }
      pcps::Archive & operator<<(                       const double val ) { return this->write(val); }
      pcps::Archive & operator<<(                  const long double val ) { return this->write(val); }
      pcps::Archive & operator<<(        const std::complex<double>& val ) { return this->write(val); }
      pcps::Archive & operator<<(                        const void* val ) { return this->write(val); }
      pcps::Archive & operator<<(                         const char val ) { return this->write(val); }
      pcps::Archive & operator<<(                  const signed char val ) { return this->write(val); }
      pcps::Archive & operator<<(                const unsigned char val ) { return this->write(val); }

      //pcps::Archive & operator<<(                    std::streambuf*  sb ) { *_s << " " <<  sb; return *this; }

      pcps::Archive & operator<<(                        const char* str ) { return *this << std::string(str); }
      //pcps::Archive & operator<<(                 const signed char* str ) { *_s << " " << str; return *this; }
      //pcps::Archive & operator<<(               const unsigned char* str ) { *_s << " " << str; return *this; }
      pcps::Archive & operator<<(                const std::string & val ) {
        return *this << std::vector<char>(val.begin(), val.end());
      }

      pcps::Archive & operator<<(   std::ostream& ( *pf )(std::ostream&) ) { return *this; }
      pcps::Archive & operator<<(           std::ios& ( *pf )(std::ios&) ) { return *this; }
      pcps::Archive & operator<<( std::ios_base& ( *pf )(std::ios_base&) ) { return *this; }

      pcps::Archive & operator<<(          const std::vector<short>& val ) { return this->write(val); }
      pcps::Archive & operator<<( const std::vector<unsigned short>& val ) { return this->write(val); }
      pcps::Archive & operator<<(            const std::vector<int>& val ) { return this->write(val); }
      pcps::Archive & operator<<(   const std::vector<unsigned int>& val ) { return this->write(val); }
      pcps::Archive & operator<<(           const std::vector<long>& val ) { return this->write(val); }
      pcps::Archive & operator<<(  const std::vector<unsigned long>& val ) { return this->write(val); }
      pcps::Archive & operator<<(          const std::vector<float>& val ) { return this->write(val); }
      pcps::Archive & operator<<(         const std::vector<double>& val ) { return this->write(val); }
      pcps::Archive & operator<<(    const std::vector<long double>& val ) { return this->write(val); }
      pcps::Archive & operator<<(           const std::vector<char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(    const std::vector<signed char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(  const std::vector<unsigned char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(    const std::vector<std::string>& val ) { return this->write(val); }
      pcps::Archive & operator<<( const std::vector<std::complex<double> >& val ) { return this->write(val); }

      pcps::Archive & operator<<(             const std::set<short>& val ) { return this->write(val); }
      pcps::Archive & operator<<(    const std::set<unsigned short>& val ) { return this->write(val); }
      pcps::Archive & operator<<(               const std::set<int>& val ) { return this->write(val); }
      pcps::Archive & operator<<(      const std::set<unsigned int>& val ) { return this->write(val); }
      pcps::Archive & operator<<(              const std::set<long>& val ) { return this->write(val); }
      pcps::Archive & operator<<(     const std::set<unsigned long>& val ) { return this->write(val); }
      pcps::Archive & operator<<(              const std::set<char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(       const std::set<signed char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(     const std::set<unsigned char>& val ) { return this->write(val); }
      pcps::Archive & operator<<(       const std::set<std::string>& val ) { return this->write(val); }

  };

  class BinaryArchive : public pcps::BinaryArchiveTemplate<std::stringstream> {

    private:

      /// \brief  the copy constructor is disabled
      BinaryArchive(const BinaryArchive &);

      /// \brief  the assignment operator is disabled
      BinaryArchive & operator=(const BinaryArchive &);

    public:

      BinaryArchive() {
        _s = boost::shared_ptr<std::stringstream>( new std::stringstream() );
      }

      ~BinaryArchive() {} //{ std::cout << "destroyed BinaryArchive" << std::endl; }

  };

  class BinaryFileArchive : public pcps::BinaryArchiveTemplate<std::fstream> {

    private:

      /// \brief  the copy constructor is disabled
      BinaryFileArchive(const BinaryFileArchive &);

      /// \brief  the assignment operator is disabled
      BinaryFileArchive & operator=(const BinaryFileArchive &);

    public:

      BinaryFileArchive(const std::string & filename, const std::string & mode = "rwt") {

        // get the mode in which to open the file
        std::ios_base::openmode which;
        if      (mode == "r")
          which = std::ios_base::binary | std::ios_base::in;
        else if (mode == "w")
          which = std::ios_base::binary | std::ios_base::out;
        else if (mode == "wt")
          which = std::ios_base::binary | std::ios_base::out | std::ios_base::trunc;
        else if (mode == "rw")
          which = std::ios_base::binary | std::ios_base::in | std::ios_base::out;
        else if (mode == "rwt")
          which = std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc;
        else
          throw pcps::Exception("mode for BinaryFileArchive must be \"r\", \"w\", \"wt\", \"rw\", or \"rwt\"");

        // open the file
        _s = boost::shared_ptr<std::fstream>( new std::fstream(filename.c_str(), which) );

        // verify file is open
        if (!_s->is_open())
          throw pcps::Exception("Failed to open file \"%s\" in BinaryFileArchive constructor.") % filename;

      }

      ~BinaryFileArchive() {
        _s->close();
        //std::cout << "destroyed BinaryFileArchive" << std::endl;
      }

  };

//  class TextFile : public std::fstream {
//
//    pcps::TextArchive _ta;
//    pcps::TextFileArchive _tfa;
//
//    public:
//
//      TextFile(const std::string & filename, const std::string & mode)
//        : _ta(),
//          _tfa("__temp.txt")
//      {
//
//        // open the file
//        if (mode == "r")
//          this->open(filename.c_str(), std::ios_base::in);
//        else if (mode == "w")
//          this->open(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
//        else
//          throw pcps::Exception("Text file mode must be \"r\" or \"w\".");
//
//        // verify file is open
//        if (!this->is_open())
//          throw pcps::Exception("Failed to open file \"%s\" in TextFile constructor.") % filename;
//
//      }
//
//      template<class T> TextFile & operator<<(const std::vector<T> & t) {
//        for (size_t i = 0; i < t.size(); i++)
//          (*this) << t[i] << std::endl;
//      }
//
//  };
//
//  ///////////////////////////////////////////////////////////////////////////////////////////////////
//  /// \brief   Class for archiving data in binary format.
//  ///
//  /// Archiving can be done using either an in-memory buffer or a file on disk.
//  /// The default constructor creates an archive with an in-memory buffer.
//  /// The file constructor creates an archive with a read-access or write-access file on disk.
//  ///
//  ///////////////////////////////////////////////////////////////////////////////////////////////////
//  class BinaryArchive {
//
//    private:
//
//      /// \brief  Whether we are reading from a file ('r'), writing to a file ('w'), or reading
//      ///         and writing to a buffer in memory ('x').
//      const char _mode;
//
//      /// \brief  position in the memory buffer where the next data will be written to
//      size_t _put_pos;
//
//      /// \brief  position in the memory buffer where the next data will be read from
//      size_t _get_pos;
//
//      /// \brief  the file we are reading to or writing from
//      std::fstream _f;
//
//      /// \brief  the in-memory buffer
//      std::vector<char> _b;
//
//      /// \brief  disable copy constructor
//      BinaryArchive(const BinaryArchive &);
//
//      /// \brief  disable assignment operator
//      BinaryArchive & operator=(const BinaryArchive &);
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  write data to the in-memory buffer
//      ///
//      /// \param[in]     n         The number of data elements to be written.
//      /// \param[in]     ptr       A pointer to the data elements.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> void add_to_buffer(const size_t n, const T * ptr) {
//
//        // check mode
//        if ( _mode != 'x' )
//          throw pcps::Exception("BinaryArchive::add_to_buffer not allowed in file reading or writing mode");
//
//        // enlarge buffer if necessary
//        if ( _put_pos + n * sizeof(T) > _b.size() )
//          _b.resize(_put_pos + n * sizeof(T));
//
//        // copy the data to the buffer
//        std::memcpy(&_b[0] + _put_pos, ptr, n * sizeof(T));
//
//        // update the put position
//        _put_pos += n * sizeof(T);
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  read data from the in-memory buffer
//      ///
//      /// \param[in]     n         The number of data elements to read.
//      /// \param[in,out] ptr       A pointer to where we will place the data read from the buffer.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> void get_from_buffer(const size_t n, T * ptr) {
//
//        // check mode
//        if ( _mode != 'x' )
//          throw pcps::Exception("BinaryArchive::get_from_buffer not allowed file reading or writing mode");
//
//        // check that the buffer has enough elements remaining
//        if ( _get_pos + n * sizeof(T) > _put_pos )
//          throw pcps::Exception("overran buffer in BinaryArchive::get_from_buffer");
//
//        // copy the data from the buffer
//        std::memcpy(ptr, &_b[0] + _get_pos, n * sizeof(T));
//
//        // update the get position
//        _get_pos += n * sizeof(T);
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  read data from the file
//      ///
//      /// \param[in]     n         The number of data elements to read.
//      /// \param[in,out] ptr       A pointer to where we will place the data read from the file.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> void get_from_file(const size_t n, T * ptr) {
//
//        // check mode
//        if ( _mode != 'r' )
//          throw pcps::Exception("BinaryArchive::get_from_file only allowed in file reading mode");
//
//        // read the data
//        _f.read((char *)ptr, n * sizeof(T));
//
//        // check that the end of the file was not reached
//        if ( _f.eof() )
//          throw pcps::Exception("reached the end of the file while reading data in BinaryArchive::get_from_file");
//
//      }
//
//    public:
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Default constructor, which places the archive in the in-memory mode.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive() : _mode('x'), _get_pos(0), _put_pos(0), _f(), _b(1) {}
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  File constructor, which places the archive in either file-reading or file-writing mode.
//      ///
//      /// \param[in]     filename  The name of the file to use.
//      /// \param[in]     mode      Whether we are reading or writing the file.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive(const std::string & filename, const char mode)
//        : _mode(mode),
//          _get_pos(0),
//          _put_pos(0),
//          _f(),
//          _b(1)
//      {
//
//        // open the file
//        if (_mode == 'r')
//          _f.open(filename.c_str(), std::fstream::in | std::fstream::binary);
//        else if (_mode == 'w')
//          _f.open(filename.c_str(), std::fstream::out | std::fstream::trunc | std::fstream::binary);
//        else
//          throw pcps::Exception("BinaryArchive file mode must be 'r' or 'w'.");
//
//        // verify file is open
//        if (!_f.is_open())
//          throw pcps::Exception("Failed to open file \"%s\" in BinaryArchive constructor.") % filename;
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Destructor, which closes the file if we are in file mode.
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      ~BinaryArchive() {
//
//        if (_mode == 'r' || _mode == 'w')
//          _f.close();
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Resets an in-memory archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      void clear() {
//        
//        // check mode
//        if ( _mode != 'x' )
//          throw pcps::Exception("BinaryArchive::clear not allowed in file reading or writing mode");
//
//        // reset the buffer and read and write positions
//        _get_pos = 0;
//        _put_pos = 0;
//        _b.resize(1);
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Writes an object to the archive.
//      ///
//      /// \param[in]     t         The object to be archived.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> BinaryArchive & operator<<(const T & t) {
//
//        // to binary file
//        if ( _mode == 'w' )
//          _f.write((const char *)&t, sizeof(T));
//
//        // to buffer
//        else if ( _mode == 'x' )
//          this->add_to_buffer(1, &t);
//
//        // wrong mode
//        else
//          throw pcps::Exception("BinaryArchive << operator only allowed in writing mode");
//
//        // return a reference to the archive
//        return *this;
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Writes a vector to the archive.
//      ///
//      /// \param[in]     t         The vector to be archived.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> BinaryArchive & operator<<(const std::vector<T> & t) {
//
//        const size_t n = t.size();
//
//        // to binary file
//        if ( _mode == 'w' ) {
//
//          _f.write((const char *)&n, sizeof(size_t));
//          if (n > 0)
//            _f.write((const char *)&t[0], n * sizeof(T));
//
//        // to buffer
//        } else if ( _mode == 'x' ) {
//
//          this->add_to_buffer(1, &n);
//          if (n > 0)
//            this->add_to_buffer(n, &t[0]);
//
//        // wrong mode
//        } else
//          throw pcps::Exception("BinaryArchive << operator only allowed in writing mode");
//
//        // return a reference to the archive
//        return *this;
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Writes a vector of bools to the archive.
//      ///
//      /// \param[in]     t         The vector to be archived.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive & operator<<(const std::vector<bool> & t) {
//        throw pcps::Exception("No implementation of BinaryArchive for vector of bool.");
//        return *this;
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Writes a string (std::string) to the archive.
//      ///
//      /// \param[in]     s         The string to be archived.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive & operator<<(const std::string & s) {
//        (*this) << std::vector<char>(s.begin(), s.end());
//        return *this;
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Writes a string (const char *) to the archive.
//      ///
//      /// \param[in]     s         The string to be archived.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive & operator<<(const char * s) {
//        (*this) << std::string(s);
//        return *this;
//      }
//
//      /// \brief  ignore manipulators
//      BinaryArchive & operator<<( std::ostream & (*pf)( std::ostream &)) {}
//      /// \brief  ignore manipulators
//      BinaryArchive & operator<<(     std::ios & (*pf)(     std::ios &)) {}
//      /// \brief  ignore manipulators
//      BinaryArchive & operator<<(std::ios_base & (*pf)(std::ios_base &)) {}
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Reads an object from the archive.
//      ///
//      /// \param[in]     t         The object to be read.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> BinaryArchive & operator>>(T & t) {
//
//        // from binary file
//        if ( _mode == 'r' )
//          this->get_from_file(1, &t);
//
//        // from buffer
//        else if ( _mode == 'x' )
//          this->get_from_buffer(1, &t);
//
//        // wrong mode
//        else
//          throw pcps::Exception("BinaryArchive >> operator only allowed in reading mode");
//
//        // return a reference to the archive
//        return *this;
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Reads a vector from the archive.
//      ///
//      /// \param[in]     t         The vector to be read.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      template<class T> BinaryArchive & operator>>(std::vector<T> & t) {
//
//        size_t n;
//
//        // from binary file
//        if ( _mode == 'r' ) {
//
//          this->get_from_file(1, &n);
//          t.resize(n);
//          if (n > 0)
//            this->get_from_file(n, &t[0]);
//
//        // from buffer
//        } else if ( _mode == 'x' ) {
//
//          this->get_from_buffer(1, &n);
//          t.resize(n);
//          if (n > 0)
//            this->get_from_buffer(n, &t[0]);
//
//        // wrong mode
//        } else
//          throw pcps::Exception("BinaryArchive >> operator only allowed in reading mode");
//
//        // return a reference to the archive
//        return *this;
//
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Reads a vector of bools from the archive.
//      ///
//      /// \param[in]     t         The vector to be read.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive & operator>>(std::vector<bool> & t) {
//        throw pcps::Exception("No implementation of BinaryArchive for vector of bool.");
//        return *this;
//      }
//
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief  Reads a string (std::string) from the archive.
//      ///
//      /// \param[in]     s         The string to be read.
//      ///
//      /// \return a reference to the archive
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      BinaryArchive & operator>>(std::string & s) {
//        std::vector<char> v;
//        (*this) >> v;
//        s = std::string(v.begin(), v.end());
//        return *this;
//      }
//
//  };

}

#endif
